home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / cvs-1.8 / cvs-1 / cvs-1.8.1 / windows-NT / filesubr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-06  |  19.3 KB  |  866 lines

  1. /* filesubr.c --- subroutines for dealing with files
  2.    Jim Blandy <jimb@cyclic.com>
  3.  
  4.    This file is part of GNU CVS.
  5.  
  6.    GNU CVS is free software; you can redistribute it and/or modify it
  7.    under the terms of the GNU General Public License as published by the
  8.    Free Software Foundation; either version 2, or (at your option) any
  9.    later version.
  10.  
  11.    This program is distributed in the hope that it will be useful,
  12.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with this program; if not, write to the Free Software
  18.    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /* These functions were moved out of subr.c because they need different
  21.    definitions under operating systems (like, say, Windows NT) with different
  22.    file system semantics.  */
  23.  
  24. #include <io.h>
  25. #include <windows.h>
  26.  
  27. #include "cvs.h"
  28.  
  29. /*
  30.  * I don't know of a convenient way to test this at configure time, or else
  31.  * I'd certainly do it there.
  32.  */
  33. #if defined(NeXT)
  34. #define LOSING_TMPNAM_FUNCTION
  35. #endif
  36.  
  37. static int deep_remove_dir PROTO((const char *path));
  38.  
  39. /*
  40.  * Copies "from" to "to".
  41.  */
  42. void
  43. copy_file (from, to)
  44.     const char *from;
  45.     const char *to;
  46. {
  47.     struct stat sb;
  48.     struct utimbuf t;
  49.     int fdin, fdout;
  50.  
  51.     if (trace)
  52. #ifdef SERVER_SUPPORT
  53.     (void) fprintf (stderr, "%c-> copy(%s,%s)\n",
  54.             (server_active) ? 'S' : ' ', from, to);
  55. #else
  56.     (void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
  57. #endif
  58.     if (noexec)
  59.     return;
  60.  
  61.     if ((fdin = open (from, O_RDONLY | O_BINARY)) < 0)
  62.     error (1, errno, "cannot open %s for copying", from);
  63.     if (fstat (fdin, &sb) < 0)
  64.     error (1, errno, "cannot fstat %s", from);
  65.     if ((fdout = creat (to, (int) sb.st_mode & 07777)) < 0)
  66.     error (1, errno, "cannot create %s for copying", to);
  67.     if (sb.st_size > 0)
  68.     {
  69.     char buf[BUFSIZ];
  70.     int n;
  71.  
  72.     for (;;) 
  73.     {
  74.         n = read (fdin, buf, sizeof(buf));
  75.         if (n == -1)
  76.         {
  77. #ifdef EINTR
  78.         if (errno == EINTR)
  79.             continue;
  80. #endif
  81.         error (1, errno, "cannot read file %s for copying", from);
  82.         }
  83.             else if (n == 0) 
  84.         break;
  85.   
  86.         if (write(fdout, buf, n) != n) {
  87.         error (1, errno, "cannot write file %s for copying", to);
  88.         }
  89.     }
  90.  
  91. #ifdef HAVE_FSYNC
  92.     if (fsync (fdout)) 
  93.         error (1, errno, "cannot fsync file %s after copying", to);
  94. #endif
  95.     }
  96.  
  97.     if (close (fdin) < 0) 
  98.     error (0, errno, "cannot close %s", from);
  99.     if (close (fdout) < 0)
  100.     error (1, errno, "cannot close %s", to);
  101.  
  102.     /* now, set the times for the copied file to match those of the original */
  103.     memset ((char *) &t, 0, sizeof (t));
  104.     t.actime = sb.st_atime;
  105.     t.modtime = sb.st_mtime;
  106.     (void) utime (to, &t);
  107. }
  108.  
  109. /*
  110.  * link a file, if possible.  Warning: the Windows NT version of this
  111.  * function just copies the file, so only use this function in ways
  112.  * that can deal with either a link or a copy.
  113.  */
  114. int
  115. link_file (from, to)
  116.     const char *from;
  117.     const char *to;
  118. {
  119.     copy_file (from, to);
  120.     return 0;
  121. }
  122.  
  123. /* FIXME-krp: these functions would benefit from caching the char * &
  124.    stat buf.  */
  125.  
  126. /*
  127.  * Returns non-zero if the argument file is a directory, or is a symbolic
  128.  * link which points to a directory.
  129.  */
  130. int
  131. isdir (file)
  132.     const char *file;
  133. {
  134.     struct stat sb;
  135.  
  136.     if (stat (file, &sb) < 0)
  137.     return (0);
  138.     return (S_ISDIR (sb.st_mode));
  139. }
  140.  
  141. /*
  142.  * Returns non-zero if the argument file is a symbolic link.
  143.  */
  144. int
  145. islink (file)
  146.     const char *file;
  147. {
  148. #ifdef S_ISLNK
  149.     struct stat sb;
  150.  
  151.     if (lstat (file, &sb) < 0)
  152.     return (0);
  153.     return (S_ISLNK (sb.st_mode));
  154. #else
  155.     return (0);
  156. #endif
  157. }
  158.  
  159. /*
  160.  * Returns non-zero if the argument file exists.
  161.  */
  162. int
  163. isfile (file)
  164.     const char *file;
  165. {
  166.     return isaccessible(file, F_OK);
  167. }
  168.  
  169. /*
  170.  * Returns non-zero if the argument file is readable.
  171.  */
  172. int
  173. isreadable (file)
  174.     const char *file;
  175. {
  176.     return isaccessible(file, R_OK);
  177. }
  178.  
  179. /*
  180.  * Returns non-zero if the argument file is writable.
  181.  */
  182. int
  183. iswritable (file)
  184.     const char *file;
  185. {
  186.     return isaccessible(file, W_OK);
  187. }
  188.  
  189. /*
  190.  * Returns non-zero if the argument file is accessable according to
  191.  * mode.  If compiled with SETXID_SUPPORT also works if cvs has setxid
  192.  * bits set.
  193.  */
  194. int
  195. isaccessible (file, mode)
  196.     const char *file;
  197.     const int mode;
  198. {
  199. #ifdef SETXID_SUPPORT
  200.     struct stat sb;
  201.     int umask = 0;
  202.     int gmask = 0;
  203.     int omask = 0;
  204.     int uid;
  205.     
  206.     if (stat(file, &sb) == -1)
  207.     return 0;
  208.     if (mode == F_OK)
  209.     return 1;
  210.  
  211.     uid = geteuid();
  212.     if (uid == 0)        /* superuser */
  213.     {
  214.     if (mode & X_OK)
  215.         return sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH);
  216.     else
  217.         return 1;
  218.     }
  219.     
  220.     if (mode & R_OK)
  221.     {
  222.     umask |= S_IRUSR;
  223.     gmask |= S_IRGRP;
  224.     omask |= S_IROTH;
  225.     }
  226.     if (mode & W_OK)
  227.     {
  228.     umask |= S_IWUSR;
  229.     gmask |= S_IWGRP;
  230.     omask |= S_IWOTH;
  231.     }
  232.     if (mode & X_OK)
  233.     {
  234.     umask |= S_IXUSR;
  235.     gmask |= S_IXGRP;
  236.     omask |= S_IXOTH;
  237.     }
  238.  
  239.     if (sb.st_uid == uid)
  240.     return (sb.st_mode & umask) == umask;
  241.     else if (sb.st_gid == getegid())
  242.     return (sb.st_mode & gmask) == gmask;
  243.     else
  244.     return (sb.st_mode & omask) == omask;
  245. #else
  246.     return access(file, mode) == 0;
  247. #endif
  248. }
  249.  
  250. /*
  251.  * Open a file and die if it fails
  252.  */
  253. FILE *
  254. open_file (name, mode)
  255.     const char *name;
  256.     const char *mode;
  257. {
  258.     FILE *fp;
  259.  
  260.     if ((fp = fopen (name, mode)) == NULL)
  261.     error (1, errno, "cannot open %s", name);
  262.     return (fp);
  263. }
  264.  
  265. /*
  266.  * Make a directory and die if it fails
  267.  */
  268. void
  269. make_directory (name)
  270.     const char *name;
  271. {
  272.     struct stat sb;
  273.  
  274.     if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode)))
  275.         error (0, 0, "%s already exists but is not a directory", name);
  276.     if (!noexec && mkdir (name) < 0)
  277.     error (1, errno, "cannot make directory %s", name);
  278. }
  279.  
  280. /*
  281.  * Make a path to the argument directory, printing a message if something
  282.  * goes wrong.
  283.  */
  284. void
  285. make_directories (name)
  286.     const char *name;
  287. {
  288.     char *cp;
  289.  
  290.     if (noexec)
  291.     return;
  292.  
  293.     if (mkdir (name) == 0 || errno == EEXIST)
  294.     return;
  295.     if (errno != ENOENT)
  296.     {
  297.     error (0, errno, "cannot make path to %s", name);
  298.     return;
  299.     }
  300.     if ((cp = strrchr (name, '/')) == NULL)
  301.     return;
  302.     *cp = '\0';
  303.     make_directories (name);
  304.     *cp++ = '/';
  305.     if (*cp == '\0')
  306.     return;
  307.     (void) mkdir (name);
  308. }
  309.  
  310. /*
  311.  * Change the mode of a file, either adding write permissions, or removing
  312.  * all write permissions.  Adding write permissions honors the current umask
  313.  * setting.
  314.  */
  315. void
  316. xchmod (fname, writable)
  317.     char *fname;
  318.     int writable;
  319. {
  320.     struct stat sb;
  321.     mode_t mode, oumask;
  322.  
  323.     if (stat (fname, &sb) < 0)
  324.     {
  325.     if (!noexec)
  326.         error (0, errno, "cannot stat %s", fname);
  327.     return;
  328.     }
  329.     if (writable)
  330.     {
  331.     oumask = umask (0);
  332.     (void) umask (oumask);
  333.     mode = sb.st_mode | ~oumask & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0) |
  334.                        ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0) |
  335.                        ((sb.st_mode & S_IROTH) ? S_IWOTH : 0));
  336.     }
  337.     else
  338.     {
  339.     mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH);
  340.     }
  341.  
  342.     if (trace)
  343. #ifdef SERVER_SUPPORT
  344.     (void) fprintf (stderr, "%c-> chmod(%s,%o)\n",
  345.             (server_active) ? 'S' : ' ', fname, mode);
  346. #else
  347.     (void) fprintf (stderr, "-> chmod(%s,%o)\n", fname, mode);
  348. #endif
  349.     if (noexec)
  350.     return;
  351.  
  352.     if (chmod (fname, mode) < 0)
  353.     error (0, errno, "cannot change mode of file %s", fname);
  354. }
  355.  
  356.  
  357. /* Read the value of a symbolic link.
  358.    Under Windows NT, this function always returns EINVAL.  */
  359. int
  360. readlink (char *path, char *buf, int buf_size)
  361. {
  362.     errno = EINVAL;
  363.     return -1;
  364. }
  365.  
  366. /*
  367.  * Rename a file and die if it fails
  368.  */
  369. void
  370. rename_file (from, to)
  371.     const char *from;
  372.     const char *to;
  373. {
  374.     if (trace)
  375. #ifdef SERVER_SUPPORT
  376.     (void) fprintf (stderr, "%c-> rename(%s,%s)\n",
  377.             (server_active) ? 'S' : ' ', from, to);
  378. #else
  379.     (void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
  380. #endif
  381.     if (noexec)
  382.     return;
  383.  
  384.     /* Win32 unlink is stupid --- it fails if the file is read-only  */
  385.     chmod(to, S_IWRITE);
  386.     unlink(to);
  387.     if (rename (from, to) < 0)
  388.     error (1, errno, "cannot rename file %s to %s", from, to);
  389. }
  390.  
  391. /* Windows NT doesn't have hard links or symbolic links.
  392.    There was only one place in CVS which used this function,
  393.    so I rewrote it to work another way, so this function isn't
  394.    used any more.  */
  395. #if 0
  396. /*
  397.  * link a file, if possible.
  398.  */
  399. int
  400. link_file (from, to)
  401.     const char *from;
  402.     const char *to;
  403. {
  404.     if (trace)
  405. #ifdef SERVER_SUPPORT
  406.     (void) fprintf (stderr, "%c-> link(%s,%s)\n",
  407.             (server_active) ? 'S' : ' ', from, to);
  408. #else
  409.     (void) fprintf (stderr, "-> link(%s,%s)\n", from, to);
  410. #endif
  411.     if (noexec)
  412.     return (0);
  413.  
  414.     return (link (from, to));
  415. }
  416. #endif
  417.  
  418. /*
  419.  * unlink a file, if possible.
  420.  */
  421. int
  422. unlink_file (f)
  423.     const char *f;
  424. {
  425.     if (trace)
  426. #ifdef SERVER_SUPPORT
  427.     (void) fprintf (stderr, "%c-> unlink(%s)\n",
  428.             (server_active) ? 'S' : ' ', f);
  429. #else
  430.     (void) fprintf (stderr, "-> unlink(%s)\n", f);
  431. #endif
  432.     if (noexec)
  433.     return (0);
  434.  
  435.     /* Win32 unlink is stupid - it fails if the file is read-only */
  436.     chmod (f, _S_IWRITE);
  437.     return (unlink (f));
  438. }
  439.  
  440. /*
  441.  * Unlink a file or dir, if possible.  If it is a directory do a deep
  442.  * removal of all of the files in the directory.  Return -1 on error
  443.  * (in which case errno is set).
  444.  */
  445. int
  446. unlink_file_dir (f)
  447.     const char *f;
  448. {
  449.     if (trace)
  450. #ifdef SERVER_SUPPORT
  451.     (void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n",
  452.             (server_active) ? 'S' : ' ', f);
  453. #else
  454.     (void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f);
  455. #endif
  456.     if (noexec)
  457.     return (0);
  458.  
  459.     /* Win32 unlink is stupid - it fails if the file is read-only */
  460.     chmod (f, _S_IWRITE);
  461.     if (unlink (f) != 0)
  462.     {
  463.     /* under Windows NT, unlink returns EACCES if the path
  464.        is a directory.  */
  465.         if (errno == EISDIR || errno == EACCES)
  466.                 return deep_remove_dir (f);
  467.         else
  468.         /* The file wasn't a directory and some other
  469.          * error occured
  470.          */
  471.                 return -1;
  472.     }
  473.     /* We were able to remove the file from the disk */
  474.     return 0;
  475. }
  476.  
  477. /* Remove a directory and everything it contains.  Returns 0 for
  478.  * success, -1 for failure (in which case errno is set).
  479.  */
  480.  
  481. static int
  482. deep_remove_dir (path)
  483.     const char *path;
  484. {
  485.     DIR          *dirp;
  486.     struct dirent *dp;
  487.     char       buf[PATH_MAX];
  488.  
  489.     if ( rmdir (path) != 0 && errno == ENOTEMPTY )
  490.     {
  491.     if ((dirp = opendir (path)) == NULL)
  492.         /* If unable to open the directory return
  493.          * an error
  494.          */
  495.         return -1;
  496.  
  497.     while ((dp = readdir (dirp)) != NULL)
  498.     {
  499.         if (strcmp (dp->d_name, ".") == 0 ||
  500.             strcmp (dp->d_name, "..") == 0)
  501.         continue;
  502.  
  503.         sprintf (buf, "%s/%s", path, dp->d_name);
  504.  
  505.         /* Win32 unlink is stupid - it fails if the file is read-only */
  506.         chmod (buf, _S_IWRITE);
  507.         if (unlink (buf) != 0 )
  508.         {
  509.         if (errno == EISDIR || errno == EACCES)
  510.         {
  511.             if (deep_remove_dir (buf))
  512.             {
  513.             closedir (dirp);
  514.             return -1;
  515.             }
  516.         }
  517.         else
  518.         {
  519.             /* buf isn't a directory, or there are
  520.              * some sort of permision problems
  521.              */
  522.             closedir (dirp);
  523.             return -1;
  524.         }
  525.         }
  526.     }
  527.     closedir (dirp);
  528.     return rmdir (path);
  529.     }
  530.     /* Was able to remove the directory return 0 */
  531.     return 0;
  532. }
  533.  
  534. /* Read NCHARS bytes from descriptor FD into BUF.
  535.    Return the number of characters successfully read.
  536.    The number returned is always NCHARS unless end-of-file or error.  */
  537. static size_t
  538. block_read (fd, buf, nchars)
  539.     int fd;
  540.     char *buf;
  541.     size_t nchars;
  542. {
  543.     char *bp = buf;
  544.     size_t nread;
  545.  
  546.     do 
  547.     {
  548.     nread = read (fd, bp, nchars);
  549.     if (nread == (size_t)-1)
  550.     {
  551. #ifdef EINTR
  552.         if (errno == EINTR)
  553.         continue;
  554. #endif
  555.         return (size_t)-1;
  556.     }
  557.  
  558.     if (nread == 0)
  559.         break; 
  560.  
  561.     bp += nread;
  562.     nchars -= nread;
  563.     } while (nchars != 0);
  564.  
  565.     return bp - buf;
  566.  
  567.     
  568. /*
  569.  * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
  570.  */
  571. int
  572. xcmp (file1, file2)
  573.     const char *file1;
  574.     const char *file2;
  575. {
  576.     char *buf1, *buf2;
  577.     struct stat sb1, sb2;
  578.     int fd1, fd2;
  579.     int ret;
  580.  
  581.     if ((fd1 = open (file1, O_RDONLY | O_BINARY)) < 0)
  582.     error (1, errno, "cannot open file %s for comparing", file1);
  583.     if ((fd2 = open (file2, O_RDONLY | O_BINARY)) < 0)
  584.     error (1, errno, "cannot open file %s for comparing", file2);
  585.     if (fstat (fd1, &sb1) < 0)
  586.     error (1, errno, "cannot fstat %s", file1);
  587.     if (fstat (fd2, &sb2) < 0)
  588.     error (1, errno, "cannot fstat %s", file2);
  589.  
  590.     /* A generic file compare routine might compare st_dev & st_ino here 
  591.        to see if the two files being compared are actually the same file.
  592.        But that won't happen in CVS, so we won't bother. */
  593.  
  594.     if (sb1.st_size != sb2.st_size)
  595.     ret = 1;
  596.     else if (sb1.st_size == 0)
  597.     ret = 0;
  598.     else
  599.     {
  600.     /* FIXME: compute the optimal buffer size by computing the least
  601.        common multiple of the files st_blocks field */
  602.     size_t buf_size = 8 * 1024;
  603.     size_t read1;
  604.     size_t read2;
  605.  
  606.     buf1 = xmalloc (buf_size);
  607.     buf2 = xmalloc (buf_size);
  608.  
  609.     do 
  610.     {
  611.         read1 = block_read (fd1, buf1, buf_size);
  612.         if (read1 == (size_t)-1)
  613.         error (1, errno, "cannot read file %s for comparing", file1);
  614.  
  615.         read2 = block_read (fd2, buf2, buf_size);
  616.         if (read2 == (size_t)-1)
  617.         error (1, errno, "cannot read file %s for comparing", file2);
  618.  
  619.         /* assert (read1 == read2); */
  620.  
  621.         ret = memcmp(buf1, buf2, read1);
  622.     } while (ret == 0 && read1 == buf_size);
  623.  
  624.     free (buf1);
  625.     free (buf2);
  626.     }
  627.     
  628.     (void) close (fd1);
  629.     (void) close (fd2);
  630.     return (ret);
  631. }
  632.  
  633.  
  634. /* The equivalence class mapping for filenames.
  635.    Windows NT filenames are case-insensitive, but case-preserving.
  636.    Both / and \ are path element separators.
  637.    Thus, this table maps both upper and lower case to lower case, and
  638.    both / and \ to /.  */
  639.  
  640. #if 0
  641. main ()
  642. {
  643.   int c;
  644.  
  645.   for (c = 0; c < 256; c++)
  646.     {
  647.       int t;
  648.  
  649.       if (c == '\\')
  650.         t = '/';
  651.       else
  652.         t = tolower (c);
  653.       
  654.       if ((c & 0x7) == 0x0)
  655.          printf ("    ");
  656.       printf ("0x%02x,", t);
  657.       if ((c & 0x7) == 0x7)
  658.          putchar ('\n');
  659.       else if ((c & 0x7) == 0x3)
  660.          putchar (' ');
  661.     }
  662. }
  663. #endif
  664.  
  665.  
  666. unsigned char
  667. WNT_filename_classes[] =
  668. {
  669.     0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,
  670.     0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f,
  671.     0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17,
  672.     0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f,
  673.     0x20,0x21,0x22,0x23, 0x24,0x25,0x26,0x27,
  674.     0x28,0x29,0x2a,0x2b, 0x2c,0x2d,0x2e,0x2f,
  675.     0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
  676.     0x38,0x39,0x3a,0x3b, 0x3c,0x3d,0x3e,0x3f,
  677.     0x40,0x61,0x62,0x63, 0x64,0x65,0x66,0x67,
  678.     0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f,
  679.     0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77,
  680.     0x78,0x79,0x7a,0x5b, 0x2f,0x5d,0x5e,0x5f,
  681.     0x60,0x61,0x62,0x63, 0x64,0x65,0x66,0x67,
  682.     0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f,
  683.     0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77,
  684.     0x78,0x79,0x7a,0x7b, 0x7c,0x7d,0x7e,0x7f,
  685.     0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87,
  686.     0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f,
  687.     0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97,
  688.     0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f,
  689.     0xa0,0xa1,0xa2,0xa3, 0xa4,0xa5,0xa6,0xa7,
  690.     0xa8,0xa9,0xaa,0xab, 0xac,0xad,0xae,0xaf,
  691.     0xb0,0xb1,0xb2,0xb3, 0xb4,0xb5,0xb6,0xb7,
  692.     0xb8,0xb9,0xba,0xbb, 0xbc,0xbd,0xbe,0xbf,
  693.     0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7,
  694.     0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf,
  695.     0xd0,0xd1,0xd2,0xd3, 0xd4,0xd5,0xd6,0xd7,
  696.     0xd8,0xd9,0xda,0xdb, 0xdc,0xdd,0xde,0xdf,
  697.     0xe0,0xe1,0xe2,0xe3, 0xe4,0xe5,0xe6,0xe7,
  698.     0xe8,0xe9,0xea,0xeb, 0xec,0xed,0xee,0xef,
  699.     0xf0,0xf1,0xf2,0xf3, 0xf4,0xf5,0xf6,0xf7,
  700.     0xf8,0xf9,0xfa,0xfb, 0xfc,0xfd,0xfe,0xff,
  701. };
  702.  
  703. /* Like strcmp, but with the appropriate tweaks for file names.
  704.    Under Windows NT, filenames are case-insensitive but case-preserving,
  705.    and both \ and / are path element separators.  */
  706. int
  707. fncmp (const char *n1, const char *n2)
  708. {
  709.     while (*n1 && *n2
  710.            && (WNT_filename_classes[(unsigned char) *n1]
  711.            == WNT_filename_classes[(unsigned char) *n2]))
  712.         n1++, n2++;
  713.     return (WNT_filename_classes[(unsigned char) *n1]
  714.             - WNT_filename_classes[(unsigned char) *n2]);
  715. }
  716.  
  717. /* Fold characters in FILENAME to their canonical forms.  
  718.    If FOLD_FN_CHAR is not #defined, the system provides a default
  719.    definition for this.  */
  720. void
  721. fnfold (char *filename)
  722. {
  723.     while (*filename)
  724.     {
  725.         *filename = FOLD_FN_CHAR (*filename);
  726.     filename++;
  727.     }
  728. }
  729.  
  730.  
  731. /* Return non-zero iff FILENAME is absolute.
  732.    Trivial under Unix, but more complicated under other systems.  */
  733. int
  734. isabsolute (filename)
  735.     const char *filename;
  736. {
  737.     return (ISDIRSEP (filename[0])
  738.             || (filename[0] != '\0'
  739.                 && filename[1] == ':'
  740.                 && ISDIRSEP (filename[2])));
  741. }
  742.  
  743. /* Return a pointer into PATH's last component.  */
  744. char *
  745. last_component (char *path)
  746. {
  747.     char *scan;
  748.     char *last = 0;
  749.  
  750.     for (scan = path; *scan; scan++)
  751.         if (ISDIRSEP (*scan))
  752.         last = scan;
  753.  
  754.     if (last)
  755.         return last + 1;
  756.     else
  757.         return path;
  758. }
  759.  
  760.  
  761. /* Read data from INFILE, and copy it to OUTFILE. 
  762.    Open INFILE using INFLAGS, and OUTFILE using OUTFLAGS.
  763.    This is useful for converting between CRLF and LF line formats.  */
  764. void
  765. convert_file (char *infile,  int inflags,
  766.           char *outfile, int outflags)
  767. {
  768.     int infd, outfd;
  769.     char buf[8192];
  770.     int len;
  771.  
  772.     if ((infd = open (infile, inflags)) < 0)
  773.         error (1, errno, "couldn't read %s", infile);
  774.     if ((outfd = open (outfile, outflags, S_IWRITE)) < 0)
  775.         error (1, errno, "couldn't write %s", outfile);
  776.  
  777.     while ((len = read (infd, buf, sizeof (buf))) > 0)
  778.         if (write (outfd, buf, len) < 0)
  779.         error (1, errno, "error writing %s", outfile);
  780.     if (len < 0)
  781.         error (1, errno, "error reading %s", infile);
  782.  
  783.     if (close (outfd) < 0)
  784.         error (0, errno, "warning: couldn't close %s", outfile);
  785.     if (close (infd) < 0)
  786.         error (0, errno, "warning: couldn't close %s", infile);
  787. }
  788.  
  789. char *
  790. get_homedir ()
  791. {
  792.     return getenv ("HOMEPATH");
  793. }
  794.  
  795. /* See cvs.h for description.  */
  796. void
  797. expand_wild (argc, argv, pargc, pargv)
  798.     int argc;
  799.     char **argv;
  800.     int *pargc;
  801.     char ***pargv;
  802. {
  803.     int i;
  804.     int new_argc;
  805.     char **new_argv;
  806.     /* Allocated size of new_argv.  We arrange it so there is always room for
  807.        one more element.  */
  808.     int max_new_argc;
  809.  
  810.     new_argc = 0;
  811.     /* Add one so this is never zero.  */
  812.     max_new_argc = argc + 1;
  813.     new_argv = (char **) xmalloc (max_new_argc * sizeof (char *));
  814.     for (i = 0; i < argc; ++i)
  815.     {
  816.     HANDLE h;
  817.     WIN32_FIND_DATA fdata;
  818.  
  819.     h = FindFirstFile (argv[i], &fdata);
  820.     if (h == INVALID_HANDLE_VALUE)
  821.     {
  822.         if (GetLastError () == ENOENT)
  823.         {
  824.         /* No match.  The file specified didn't contain a wildcard (in which case
  825.            we clearly should return it unchanged), or it contained a wildcard which
  826.            didn't match (in which case it might be better for it to be an error,
  827.            but we don't try to do that).  */
  828.         new_argv [new_argc++] = xstrdup (argv[i]);
  829.         if (new_argc == max_new_argc)
  830.         {
  831.             max_new_argc *= 2;
  832.             new_argv = xrealloc (new_argv, max_new_argc * sizeof (char *));
  833.         }
  834.         }
  835.         else
  836.         {
  837.         error (1, errno, "cannot find %s", argv[i]);
  838.         }
  839.     }
  840.     else
  841.     {
  842.         while (1)
  843.         {
  844.         new_argv [new_argc++] = xstrdup (fdata.cFileName);
  845.         if (new_argc == max_new_argc)
  846.         {
  847.             max_new_argc *= 2;
  848.             new_argv = xrealloc (new_argv, max_new_argc * sizeof (char *));
  849.         }
  850.         if (!FindNextFile (h, &fdata))
  851.         {
  852.             if (GetLastError () == ERROR_NO_MORE_FILES)
  853.             break;
  854.             else
  855.             error (1, errno, "cannot find %s", argv[i]);
  856.         }
  857.         }
  858.         if (!FindClose (h))
  859.         error (1, GetLastError (), "cannot close %s", argv[i]);
  860.     }
  861.     }
  862.     *pargc = new_argc;
  863.     *pargv = new_argv;
  864. }
  865.